package cn.whitecao.agent;

import cn.whitecao.agent.core.config.ConfigContext;
import cn.whitecao.agent.core.plugin.PluginDefinition;
import cn.whitecao.agent.core.plugin.PluginLoader;
import cn.whitecao.agent.core.plugin.PluginMatcherRule;
import cn.whitecao.agent.core.repoter.ReporterProcessor;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.io.File;
import java.lang.instrument.Instrumentation;
import java.util.List;

/**
 * @author : BashfulHuang
 **/
public class AgentInitializer extends Thread{
    private final String file = this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
    private final String parentPath = new File(file).getParent();

    private final Instrumentation inst;
    public AgentInitializer(Instrumentation inst) {
        //设置成守护线程,整个agent随着被监听的程序一起退出
        this.inst = inst;
    }

    @Override
    public void run() {
       init(this.inst);
    }

    public void init(Instrumentation inst){
        initConfig();
        initReporter();
        initPlugin(inst);
        //上报系统信息 如jvm版本操作系统版本 cpu 运行路径等不变的信息
        //初始化心跳
        //初始化 实时信息上报(内存 gc情况)
    }

    /**
     * 初始化配置文件
     */
    private void initConfig(){
        ConfigContext.load(parentPath+"/chibao-agent.properties");
    }

    /**
     * 初始化上报模块
     */
    private void initReporter(){
        ReporterProcessor.init();
    }

    private void initPlugin(Instrumentation inst){
        PluginLoader loader = new PluginLoader();
        List<PluginDefinition> pluginDefinitionList = loader.load(ConfigContext.getStr("plugin.path", parentPath + "/plugins/"));


         //byte buddy的用法参考百度

        AgentBuilder agentBuilder = new AgentBuilder.Default()
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                .disableClassFormatChanges();

        for (final PluginDefinition plugin : pluginDefinitionList) {
            List<PluginMatcherRule> ruleList = plugin.getMatcherRuleList();
            for (PluginMatcherRule pmr : ruleList) {
                AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
                    builder = builder.visit(Advice.to(plugin.getInterceptorHandlerClass()).on(pmr.getMethodsMatcher()));
                    return builder;
                };
                agentBuilder = agentBuilder.type(pmr.getTypesMatcher()).transform(transformer);
            }
            System.out.println("成功加载插件: "+plugin.getName());
        }
        agentBuilder.installOn(inst);


    }
}
